﻿#region COPYRIGHT© 2009-2013 Phillip Clark. All rights reserved.

// For licensing information see License.txt (MIT style licensing).

#endregion

using System;
using FlitBit.Parse;

namespace FlitBit.Json
{
	public sealed class JsonNumericLiteral : JsonValue
	{
		static readonly int CHashCodeSeed = typeof(JsonNumericLiteral).AssemblyQualifiedName.GetHashCode();

		decimal _value;

		public JsonNumericLiteral(decimal value)
			: base(JsonNodeKind.NumericLiteral)
		{
			_value = value;
		}

		public override bool Equals(object obj)
		{
			return (obj is JsonStringLiteral) && Equals((JsonNumericLiteral) obj);
		}

		public override int GetHashCode()
		{
			var prime = 999067;
			var code = CHashCodeSeed * prime;
			code ^= this._value.GetHashCode() * prime;
			return code;
		}

		public override TypeCode GetTypeCode()
		{
			return TypeCode.Decimal;
		}

		public override bool ToBoolean(IFormatProvider provider)
		{
			return Convert.ToBoolean(_value);
		}

		public override byte ToByte(IFormatProvider provider)
		{
			return Convert.ToByte(_value);
		}

		public override char ToChar(IFormatProvider provider)
		{
			return Convert.ToChar(_value);
		}

		public override DateTime ToDateTime(IFormatProvider provider)
		{
			return Convert.ToDateTime(_value);
		}

		public override decimal ToDecimal(IFormatProvider provider)
		{
			return _value;
		}

		public override double ToDouble(IFormatProvider provider)
		{
			return Convert.ToDouble(_value);
		}

		public override short ToInt16(IFormatProvider provider)
		{
			return Convert.ToInt16(_value);
		}

		public override int ToInt32(IFormatProvider provider)
		{
			return Convert.ToInt32(_value);
		}

		public override long ToInt64(IFormatProvider provider)
		{
			return Convert.ToInt64(_value);
		}

		public override sbyte ToSByte(IFormatProvider provider)
		{
			return Convert.ToSByte(_value);
		}

		public override float ToSingle(IFormatProvider provider)
		{
			return Convert.ToSingle(_value);
		}

		public override string ToString()
		{
			return _value.ToString();
		}

		public override string ToString(IFormatProvider provider)
		{
			return _value.ToString();
		}

		public override object ToType(Type conversionType, IFormatProvider provider)
		{
			switch (Type.GetTypeCode(conversionType))
			{
				case TypeCode.Boolean:
					return ToBoolean(provider);
				case TypeCode.Byte:
					return ToByte(provider);
				case TypeCode.Char:
					return ToChar(provider);
				case TypeCode.DateTime:
					return ToDateTime(provider);
				case TypeCode.Decimal:
					return ToDecimal(provider);
				case TypeCode.Double:
					return ToDouble(provider);
				case TypeCode.Int16:
					return ToInt16(provider);
				case TypeCode.Int32:
					return ToInt32(provider);
				case TypeCode.Int64:
					return ToInt64(provider);
				case TypeCode.Object:
					return _value;
				case TypeCode.SByte:
					return ToSByte(provider);
				case TypeCode.Single:
					return ToSingle(provider);
				case TypeCode.String:
					return ToString(provider);
				case TypeCode.UInt16:
					return ToUInt16(provider);
				case TypeCode.UInt32:
					return ToUInt32(provider);
				case TypeCode.UInt64:
					return ToUInt64(provider);
			}
			return base.ToType(conversionType, provider);
		}

		public override ushort ToUInt16(IFormatProvider provider)
		{
			return Convert.ToUInt16(_value);
		}

		public override uint ToUInt32(IFormatProvider provider)
		{
			return Convert.ToUInt32(_value);
		}

		public override ulong ToUInt64(IFormatProvider provider)
		{
			return Convert.ToUInt64(_value);
		}

		public bool Equals(JsonNumericLiteral other)
		{
			return ((object) other != null)
				&& Equals(_value, other._value);
		}

		public static bool operator ==(JsonNumericLiteral lhs, JsonNumericLiteral rhs)
		{
			if ((object) lhs == null)
			{
				return ((object) rhs == null);
			}
			else
			{
				return lhs.Equals(rhs);
			}
		}

		public static bool operator ==(JsonNumericLiteral lhs, decimal rhs)
		{
			if ((object) lhs == null)
			{
				return ((object) rhs == null);
			}
			else
			{
				return lhs._value == rhs;
			}
		}

		public static bool operator ==(decimal lhs, JsonNumericLiteral rhs)
		{
			if ((object) lhs == null)
			{
				return ((object) rhs == null);
			}
			else
			{
				return lhs == rhs._value;
			}
		}

		public static bool operator ==(JsonNumericLiteral lhs, int rhs)
		{
			if ((object) lhs == null)
			{
				return ((object) rhs == null);
			}
			else
			{
				return lhs._value == Convert.ToDecimal(rhs);
			}
		}

		public static bool operator ==(int lhs, JsonNumericLiteral rhs)
		{
			if ((object) lhs == null)
			{
				return ((object) rhs == null);
			}
			else
			{
				return Convert.ToDecimal(lhs) == rhs._value;
			}
		}

		public static implicit operator decimal(JsonNumericLiteral literal)
		{
			if ((object) literal == null)
			{
				return default(decimal);
			}
			return literal._value;
		}

		public static implicit operator JsonNumericLiteral(decimal value)
		{
			return new JsonNumericLiteral(value);
		}

		public static bool operator !=(JsonNumericLiteral lhs, JsonNumericLiteral rhs)
		{
			if ((object) lhs == null)
			{
				return ((object) rhs != null);
			}
			return !lhs.Equals(rhs);
		}

		public static bool operator !=(JsonNumericLiteral lhs, decimal rhs)
		{
			if ((object) lhs == null)
			{
				return ((object) rhs != null);
			}
			return lhs._value != rhs;
		}

		public static bool operator !=(decimal lhs, JsonNumericLiteral rhs)
		{
			if ((object) lhs == null)
			{
				return ((object) rhs != null);
			}
			return lhs != rhs._value;
		}

		public static bool operator !=(JsonNumericLiteral lhs, int rhs)
		{
			if ((object) lhs == null)
			{
				return ((object) rhs != null);
			}
			return lhs._value != Convert.ToDecimal(rhs);
		}

		public static bool operator !=(int lhs, JsonNumericLiteral rhs)
		{
			if ((object) lhs == null)
			{
				return ((object) rhs != null);
			}
			return Convert.ToDecimal(lhs) != rhs._value;
		}

		internal static JsonValue ExpectNumericLiteral(TokenizerState<JsonTokenKind> tokens)
		{
			var tk = tokens.ExpectTake(JsonTokenKind.NumericLiteral);
			return new JsonNumericLiteral(Decimal.Parse(tk.Capture.Value));
		}
	}
}